Skip to content

[pull] main from MetaMask:main#799

Merged
pull[bot] merged 24 commits into
Reality2byte:mainfrom
MetaMask:main
Jun 1, 2026
Merged

[pull] main from MetaMask:main#799
pull[bot] merged 24 commits into
Reality2byte:mainfrom
MetaMask:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Jun 1, 2026

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

FrederikBolding and others added 24 commits June 1, 2026 07:42
<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->

## **Description**

Ensure valid URLs are treated as valid by URL detection in
`SitesSearchFooter`. Additionally move out the existing regex to not
have to redeclare/recompile it for every check.

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: Fixed an issue where certain URLs would not be consider
valid in the in-app browser

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Small UI-only change to how search footer classifies input; no auth,
payments, or data-layer impact.
> 
> **Overview**
> **Sites search footer** now treats more inputs as URLs when deciding
whether to show the direct “open URL” action alongside the search-engine
link.
> 
> `looksLikeUrl` combines the existing **`is-url`** check with the prior
domain-style regex (hoisted to a module-level **`URL_REGEX`** so it
isn’t recompiled on every call). That fixes cases like
**`http://localhost:8000`** that the regex alone missed. A unit test
covers localhost URLs with a scheme.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
ae6c855. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
#30729)

<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

Homepage sections that render row-based content (token list, perps
positions, predict positions) have ~12 px of natural vertical padding
built into each row item (py-3, height: 64, or paddingVertical: 12).
Sections that render horizontal carousels or pill rails had no
equivalent padding, causing the inter-section gap to look visually
inconsistent — row sections appeared to have a larger breathing room
than carousel/pill sections.

The fix adds py-3 to the contentContainerStyle of each horizontal
carousel and pill rail on the homepage, so every section contributes the
same amount of vertical space regardless of its content type.
Additionally, ScamWarningModal and RemoveTokenBottomSheet in
TokensSection are moved outside the gap-applying container to prevent
the modal library's hidden <View> wrapper from consuming an extra 12 px
gap below the Tokens section.

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: Fixes spacing inconsistencies on the homepage

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/TMCU-816

## **Manual testing steps**

```gherkin
Feature: Homepage section spacing

  Scenario: user views the homepage with all sections visible
    Given the app is open on the homepage
    And the user has tokens, perps positions, predict positions, and top traders visible

    When user scrolls through the homepage
    Then the vertical gap between every section header and the section below it looks visually equal
    And the gap between sections is consistent regardless of whether the section shows rows or a horizontal carousel/pill rail

  Scenario: user views homepage with Perps showing pills empty state
    Given the Perps section is showing the pills rail (no open positions)
    When user views the spacing above and below the pills rail
    Then the gap matches the spacing around row-based sections like Tokens

  Scenario: user views homepage with Perps showing trending carousel
    Given the Perps section is showing the trending market tile carousel
    When user views the spacing above and below the carousel
    Then the gap matches the spacing around row-based sections like Tokens
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**
<img width="413" height="868" alt="Screenshot 2026-05-28 at 12 18 42"
src="https://github.com/user-attachments/assets/6e4b87a0-69da-480b-a33f-36eed7111df9"
/>

<!-- [screenshots/recordings] -->

### **After**
<img width="404" height="869" alt="Screenshot 2026-05-28 at 11 07 12"
src="https://github.com/user-attachments/assets/9667cccc-63b2-4e61-a914-a0d77c5618cf"
/>

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> UI-only layout and container restructuring on the wallet homepage with
no auth, data, or payment logic changes.
> 
> **Overview**
> Homepage sections now use **consistent vertical breathing room**
between headers and content. Horizontal **carousels and pill rails**
(Perps trending, Perps pills, Predict trending, Top Traders) get
**`py-3`** on their scroll content so they match row-based sections that
already pick up ~12px from list rows.
> 
> **Tokens** wraps only the header and list in the **`sectionGap`**
container and moves **`ScamWarningModal`** and
**`RemoveTokenBottomSheet`** outside it so hidden modal wrappers do not
add an extra gap under the section.
> 
> **Perps** keeps positions and orders inside a single **`SectionRow`**,
showing the skeleton in that same row while loading or trending is
pending—so loading and filled states share the same vertical padding as
other row sections.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
3f90bec. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
#30799)

<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->

## **Description**

Bump `@metamask/ai-controllers` to `^0.7.0` so market overview no longer
fails when `relatedAsset.name` or `sourceAssetId` is missing.

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Localized homepage/Perps presentation and dependency bump; no auth,
payments, or transaction logic changes.
> 
> **Overview**
> Upgrades **`@metamask/ai-controllers`** to **^0.7.0** so market
overview can return **`RelatedAsset`** entries without **`name`** or
**`sourceAssetId`**.
> 
> The Whats Happening UI now **falls back to `symbol`** for avatars,
labels, and Perps trade navigation when **`name`** is missing, and uses
**`symbol` + index** for list keys instead of **`sourceAssetId`**. New
unit tests cover sparse assets, empty trends, and confirming an empty
successful load does **not** show the error UI.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
977027e. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: bump assets controller v8.1.0

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches wallet/asset and keyring-related controller packages
transitively (including keyring-controller 26.x), so regression risk is
in balances, tokens/NFTs, and account flows rather than in local code
edits.
> 
> **Overview**
> Bumps the direct dependency **`@metamask/assets-controller`** from
**8.0.1** to **8.1.0** in `package.json`, with **`yarn.lock`** refreshed
so the resolved tree picks up that release and its transitive updates
(notably **`@metamask/assets-controllers` 108.2.0**,
**`@metamask/account-tree-controller` 7.5.0**,
**`@metamask/keyring-controller` 26.0.0**, and related
controller/backend/profile-sync/snap-account-service pins).
> 
> There are **no application source changes** in this diff—behavior
shifts, if any, come only from the upgraded packages at runtime.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
880012e. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Hardens the agentic fixture wallet setup so named fixture accounts are
created reliably and the flow tolerates legacy vaults.

1. **What is the reason for the change?** The fixture account setup was
fragile: account-group naming was loosely typed, vault unlock used a
bare `submitPassword` instead of the real post-login path, and
legacy/empty vaults could throw during init or account-tree refresh.
2. **What is the improvement/solution?** `AgenticService` now types
`queryUiTarget` visibility and `setAccountGroupName` (`AccountGroupId`),
unlocks existing vaults via `Authentication.unlockWallet`, imports each
private key gracefully, and falls back to skipping group rename for
legacy vaults instead of throwing. `setup-wallet.sh` validates the
expected HD account total, resolves an absolute `SCRIPT_DIR`, guards the
`--fixture` arg, and shares a `safe-env-parser.sh` helper.

Scope is agentic dev tooling only — no app/runtime user-facing behavior.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Agentic fixture wallet setup

  Scenario: Seed a fresh wallet from a fixture with named accounts
    Given a wallet-fixture.json defining HD and private-key accounts
    When I run scripts/perps/agentic/setup-wallet.sh
    Then the expected number of HD accounts is created
    And each account group is renamed to its fixture name
    And the script exits successfully

  Scenario: Re-run against an existing legacy vault
    Given a wallet was already seeded by a legacy run
    When I re-run setup-wallet.sh
    Then the unlock uses the real post-login flow
    And group rename is skipped without throwing
    And the run completes successfully
```

## **Screenshots/Recordings**

<!-- Dev tooling change — no UI surface. -->

### **Before**

N/A — no UI surface.

### **After**

N/A — no UI surface.

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes unlock/import paths and account-tree naming in __DEV__-only
agentic code; legacy-vault fallbacks add complexity but do not affect
production bundles.
> 
> **Overview**
> **Agentic fixture wallet setup** is reworked so Farmslot recipes can
seed named HD/private-key accounts reliably on fresh and legacy vaults.
`setupWallet` and new **`applyWalletFixture`** share
**`materializeFixtureAccounts`**: multi-SRP import via
`importNewSecretRecoveryPhrase` / `addNewHdAccount`, `count`/`names`
helpers, legacy vault fallbacks, **`Authentication.unlockWallet`**
instead of bare password submit,
**`EngineClass.disableAutomaticVaultBackup`**, and skipping account-tree
group rename when no group exists. Failures can return a **`step`**
label; the bridge adds **`queryUiTarget`**, **`refreshPerpsStreams`**,
and typed **`AccountGroupId`** usage.
> 
> **Agent Step HUD** now shows a status/progress badge (pass/fail
coloring), parses multi-line descriptions (intent + `subflow:`/`error:`
lines), and respects safe-area insets.
> 
> **Agentic scripts/docs** narrow Mobile to the CDP bridge +
preflight/`setup-wallet`/`safe-env-parser.sh`; in-repo recipe runner
pieces (`eval-ref`, pre-conditions registry, `validate-recipe` libs,
team recipes) and long perps validation docs are removed or pointed at
the external Recipe v1 runner. **`yarn a:*`** preflight scripts gain
explicit **`--mode fast|clean`**.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
80da06a. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…r clearing pasted recipient (#30771)

## **Description**

When a user pastes an address in the send flow, an auto-review
`useEffect` is triggered to streamline the UX. If the "New address"
alert modal appears and the user cancels it, then presses the "Clear"
button, the `pastedRecipient` state was not being cleared. This caused a
race condition: `handleClearInput` would set `to` to empty, which caused
`hasUnacknowledgedAlerts` to become `false` (no alerts for empty
addresses), while `pastedRecipient` and `toAddressValidated` still held
the old address. The auto-review `useEffect` would then see all
conditions pass and fire `handleSubmitPress` with an empty `to` value,
which got cast to `0x0000...0000`.

**Fix:**
1. Clear `pastedRecipient` in `handleClearInput` so the auto-review
effect cannot re-trigger with stale state after clearing.
2. Add a defense-in-depth guard in `proceedWithSubmit` to reject empty
recipient addresses.

## **Changelog**

CHANGELOG entry: Fixed a bug where clearing a pasted recipient address
in the send flow could trigger a transaction to the zero address

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Send flow clear button

  Scenario: user clears pasted address after cancelling new address alert
    Given the user is on the send recipient screen

    When user pastes a valid address using the Paste button
    And user presses the Review button
    And the "New address" alert modal appears
    And user presses Cancel on the alert modal
    And user presses the Clear button
    Then the input field is cleared
    And no transaction is submitted
    And the user remains on the recipient screen

  Scenario: user clears pasted address without triggering review first
    Given the user is on the send recipient screen

    When user pastes a valid address using the Paste button
    And user presses the Clear button before auto-review triggers
    Then the input field is cleared
    And no transaction is submitted
```

## **Screenshots/Recordings**

### **Before**

Pressing Clear after cancelling the "New address" alert triggers a
transaction submission to `0x0000...0000`.

### **After**

Pressing Clear correctly resets the input without triggering any
transaction submission.

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes send submission guards and recipient state on a user-facing
money path; scope is small and covered by tests, but incorrect gating
could block valid sends or miss edge cases.
> 
> **Overview**
> Fixes a send-flow bug where **Clear** after canceling the "New
address" alert could still auto-advance review because
**`pastedRecipient`** stayed set while **`to`** was emptied.
> 
> **`RecipientInput`** now resets **`pastedRecipient`** in
**`handleClearInput`** (along with **`updateTo('')`**) so the paste
auto-review **`useEffect`** cannot re-fire on stale paste state.
**`Recipient`** **`proceedWithSubmit`** also bails out when there is no
**`resolvedAddress`** or **`to`**, blocking submission with an empty
recipient (e.g. zero address). Tests cover clear + empty-recipient
paths.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
636fbc9. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…ed via SpaceX carousel banner (#30736)

## **Description**

Fixes the SPCX market detail leverage pill when the page is opened from
the SpaceX carousel banner. That entry path supplied route market data
with a raw placeholder `maxLeverage` value of `100`, and the detail
screen treated that as complete data instead of enriching it from the
perps market list.

The market detail screen now only skips enrichment when route
`maxLeverage` is already formatted with an `x` suffix.
Carousel/deeplink-style SPCX route params resolve to the provider market
value `5x`, while market-list entry remains unchanged.

Self-review cleanup also migrated the touched market detail `Text` and
`ButtonSemantic` usages to the non-deprecated design-system exports,
avoiding eslint-disable comments in this bug-fix diff.

Evidence is intentionally trimmed to clean, caption-free screenshots:
one before/after pair for the raw `100` to `5x` fix, plus one
watchlist-origin screenshot for AC2. Captioned runner screenshots are
omitted from the PR-visible list.

## **Changelog**

CHANGELOG entry: Fixed a bug that caused the SPCX leverage pill to show
an unformatted value when opened from the SpaceX carousel banner

## **Related issues**

Fixes:
[TAT-3262](https://consensyssoftware.atlassian.net/browse/TAT-3262)

## **Manual testing steps**

```gherkin
Feature: SPCX leverage pill

  Scenario: carousel entry shows formatted max leverage
    Given the wallet is unlocked on iOS
    When the SPCX market detail page is opened from the SpaceX carousel banner
    Then the leverage pill shows 5x instead of raw 100

  Scenario: market-list entry remains formatted
    Given the wallet is unlocked on iOS
    And SPCX is present in the watchlist-filtered market list
    When the SPCX row is pressed from the market list
    Then the leverage pill remains 5x
```

## **Screenshots/Recordings**

SPCX leverage evidence: one before/after pair for the raw carousel value
fix, plus watchlist market-list provenance for AC2.

<table>
<tr><td colspan="2"><strong>SPCX carousel entry changes from raw 100 to
formatted 5x</strong></td></tr>
<tr>
<td align="center" width="50%"><em>Before</em><br/><img
src="https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/fixes/30736/recipe-runs/inherited-7fc86479-a81c-4593-a4b0-4290c3534919/before-ac1-spcx-raw-100-clean.png?sha=6ddb5c9edd9a9ff0"
alt="before" width="400" /></td>
<td align="center" width="50%"><em>After</em><br/><img
src="https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/fixes/30736/recipe-runs/inherited-7fc86479-a81c-4593-a4b0-4290c3534919/after-ac1-spcx-5x-clean.png?sha=26e2464746202d3d"
alt="after" width="400" /></td>
</tr>
</table>

<table>
<tr><td align="center" width="50%"><strong>Watchlist-filtered market
list shows SPCX with 5x before row press</strong><br/><img
src="https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/fixes/30736/recipe-runs/inherited-7fc86479-a81c-4593-a4b0-4290c3534919/after-ac2-watchlist-spcx-row-clean.png?sha=f9292dc060f91c6d"
alt="Watchlist-filtered market list shows SPCX with 5x before row press"
width="400" /></td><td></td></tr>
</table>

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [x] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [x] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [x] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

## **Validation Recipe**

<details>
<summary>recipe.json</summary>

```json
{
  "schema_version": 1,
  "pr": "TAT-3262",
  "title": "Fix SPCX leverage pill formatting from carousel entry",
  "jira": "TAT-3262",
  "acceptance_criteria": [
    "When the SPCX market detail page is opened via the SpaceX carousel banner, then the leverage pill shows the market’s max leverage formatted as Nx.",
    "When the SPCX market detail page is opened via the market list, then the leverage pill continues to show the correctly formatted value (no regression).",
    "When the user opens the order entry screen for SPCX from either entry point, then the leverage shown there matches the pill on the market detail page."
  ],
  "validate": {
    "workflow": {
      "pre_conditions": ["wallet.unlocked", "perps.feature_enabled"],
      "entry": "ac1-open-carousel-detail",
      "nodes": {
        "ac1-open-carousel-detail": {
          "action": "navigate",
          "target": "PerpsMarketDetails",
          "params": {
            "market": {
              "symbol": "xyz:SPCX",
              "name": "SPCX",
              "price": "0",
              "change24h": "0",
              "change24hPercent": "0",
              "volume": "0",
              "marketSource": "xyz",
              "maxLeverage": "100"
            },
            "source": "carousel"
          },
          "next": "ac1-wait-leverage-viewport"
        },
        "ac1-wait-leverage-viewport": {
          "action": "wait_for",
          "test_id": "perps-leverage",
          "visibility": "viewport",
          "timeout_ms": 10000,
          "next": "ac1-wait-carousel-leverage-value"
        },
        "ac1-wait-carousel-leverage-value": {
          "action": "wait_for",
          "expression": "(function(){var txt=__AGENTIC__.getTextByTestId('perps-leverage');return JSON.stringify({leverageText:txt});})()",
          "assert": { "operator": "eq", "field": "leverageText", "value": "5x" },
          "timeout_ms": 15000,
          "next": "ac1-assert-carousel-leverage"
        },
        "ac1-assert-carousel-leverage": {
          "action": "eval_sync",
          "expression": "(function(){var route=__AGENTIC__.getRoute();var txt=__AGENTIC__.getTextByTestId('perps-leverage');return JSON.stringify({route:route?route.name:null,leverageText:txt});})()",
          "assert": {
            "all": [
              { "operator": "eq", "field": "route", "value": "PerpsMarketDetails" },
              { "operator": "eq", "field": "leverageText", "value": "5x" }
            ]
          },
          "next": "ac1-screenshot-carousel-leverage"
        },
        "ac1-screenshot-carousel-leverage": {
          "action": "screenshot",
          "filename": "evidence-ac1-carousel-leverage",
          "note": "AC1: SPCX carousel detail leverage pill visibly shows 5x",
          "claims": {
            "must_show": ["SPCX-USD", "5x"],
            "must_not_show": ["100", "Fund your wallet"]
          },
          "next": "ac2-open-market-list-origin"
        },
        "ac2-open-market-list-origin": {
          "action": "navigate",
          "target": "PerpsTrendingView",
          "params": {
            "showWatchlistOnly": true,
            "title": "Watchlist",
            "showBalanceActions": false
          },
          "next": "ac2-wait-market-list-origin"
        },
        "ac2-wait-market-list-origin": {
          "action": "wait_for",
          "route": "PerpsTrendingView",
          "timeout_ms": 10000,
          "next": "ac2-wait-spcx-watchlist-row"
        },
        "ac2-wait-spcx-watchlist-row": {
          "action": "wait_for",
          "test_id": "perps-market-row-item-xyz:SPCX",
          "timeout_ms": 15000,
          "next": "ac2-screenshot-market-list-origin"
        },
        "ac2-screenshot-market-list-origin": {
          "action": "screenshot",
          "filename": "evidence-ac2-market-list-origin",
          "note": "AC2: watchlist-filtered market list visibly contains SPCX with 5x before opening detail",
          "claims": {
            "must_show": ["Watchlist", "SPCX", "5x"],
            "must_not_show": ["SPCX-USD", "Fund your wallet"]
          },
          "next": "ac2-press-spcx-market-row"
        },
        "ac2-press-spcx-market-row": {
          "action": "press",
          "test_id": "perps-market-row-item-xyz:SPCX",
          "next": "ac2-wait-leverage-viewport"
        },
        "ac2-wait-leverage-viewport": {
          "action": "wait_for",
          "test_id": "perps-leverage",
          "visibility": "viewport",
          "timeout_ms": 10000,
          "next": "ac2-assert-market-list-leverage"
        },
        "ac2-assert-market-list-leverage": {
          "action": "eval_sync",
          "expression": "(function(){var route=__AGENTIC__.getRoute();var market=route&&route.params?route.params.market:null;var txt=__AGENTIC__.getTextByTestId('perps-leverage');return JSON.stringify({route:route?route.name:null,symbol:market?market.symbol:null,leverageText:txt});})()",
          "assert": {
            "all": [
              { "operator": "eq", "field": "route", "value": "PerpsMarketDetails" },
              { "operator": "eq", "field": "symbol", "value": "xyz:SPCX" },
              { "operator": "eq", "field": "leverageText", "value": "5x" }
            ]
          },
          "next": "ac2-screenshot-market-list-leverage"
        },
        "ac2-screenshot-market-list-leverage": {
          "action": "screenshot",
          "filename": "evidence-ac2-market-list-leverage",
          "note": "AC2: SPCX market-list detail leverage pill visibly remains 5x",
          "claims": {
            "must_show": ["SPCX-USD", "5x"],
            "must_not_show": ["100", "Fund your wallet"]
          },
          "next": "done"
        },
        "done": {
          "action": "end",
          "status": "pass"
        }
      }
    }
  }
}
```

</details>

## **Recipe Workflow**

<details>
<summary>workflow.mmd</summary>

```mermaid
flowchart TD
  %% Fix SPCX leverage pill formatting from carousel entry
  __entry__(["ENTRY"]) --> node_ac1_open_carousel_detail
  node_ac1_open_carousel_detail["ac1-open-carousel-detail<br/>navigate"]
  node_ac1_wait_leverage_viewport["ac1-wait-leverage-viewport<br/>wait_for"]
  node_ac1_wait_carousel_leverage_value["ac1-wait-carousel-leverage-value<br/>wait_for"]
  node_ac1_assert_carousel_leverage["ac1-assert-carousel-leverage<br/>eval_sync"]
  node_ac1_screenshot_carousel_leverage["ac1-screenshot-carousel-leverage<br/>screenshot"]
  node_ac2_open_market_list_origin["ac2-open-market-list-origin<br/>navigate"]
  node_ac2_wait_market_list_origin["ac2-wait-market-list-origin<br/>wait_for"]
  node_ac2_wait_spcx_watchlist_row["ac2-wait-spcx-watchlist-row<br/>wait_for"]
  node_ac2_screenshot_market_list_origin["ac2-screenshot-market-list-origin<br/>screenshot"]
  node_ac2_press_spcx_market_row["ac2-press-spcx-market-row<br/>press"]
  node_ac2_wait_leverage_viewport["ac2-wait-leverage-viewport<br/>wait_for"]
  node_ac2_assert_market_list_leverage["ac2-assert-market-list-leverage<br/>eval_sync"]
  node_ac2_screenshot_market_list_leverage["ac2-screenshot-market-list-leverage<br/>screenshot"]
  node_done(["done<br/>PASS"])
  node_ac1_open_carousel_detail --> node_ac1_wait_leverage_viewport
  node_ac1_wait_leverage_viewport --> node_ac1_wait_carousel_leverage_value
  node_ac1_wait_carousel_leverage_value --> node_ac1_assert_carousel_leverage
  node_ac1_assert_carousel_leverage --> node_ac1_screenshot_carousel_leverage
  node_ac1_screenshot_carousel_leverage --> node_ac2_open_market_list_origin
  node_ac2_open_market_list_origin --> node_ac2_wait_market_list_origin
  node_ac2_wait_market_list_origin --> node_ac2_wait_spcx_watchlist_row
  node_ac2_wait_spcx_watchlist_row --> node_ac2_screenshot_market_list_origin
  node_ac2_screenshot_market_list_origin --> node_ac2_press_spcx_market_row
  node_ac2_press_spcx_market_row --> node_ac2_wait_leverage_viewport
  node_ac2_wait_leverage_viewport --> node_ac2_assert_market_list_leverage
  node_ac2_assert_market_list_leverage --> node_ac2_screenshot_market_list_leverage
  node_ac2_screenshot_market_list_leverage --> node_done
```

</details>

[TAT-3262]:
https://consensyssoftware.atlassian.net/browse/TAT-3262?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Localized perps UI enrichment and design-system import cleanup with
new unit tests; no auth, payments, or broad trading logic changes.
> 
> **Overview**
> Fixes the **SPCX leverage pill** when market details open from the
SpaceX carousel with route `maxLeverage` of raw `100` instead of
formatted leverage.
> 
> **PerpsMarketDetailsView** now treats route leverage as complete only
when `maxLeverage` is a string ending with **`x`**. Otherwise it still
loads **`usePerpsMarkets`** and merges by symbol so the UI shows
**`5x`** and order entry gets **`defaultMaxLeverage`** from
enriched/`usePerpsMarketData` data. Touched **`Text`** /
**`ButtonSemantic`** imports move to
**`@metamask/design-system-react-native`** with updated variant/color
tokens.
> 
> Tests cover unformatted route params (with and without `xyz:` prefix),
long-button navigation defaults, and market-list navigation to SPCX with
**`perp_markets`** source.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
72df6a8. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->

## **Description**

Add `on_create` trigger mode to the triage forwarder workflow. When a
new issue is opened, it now dispatches to `triage-agent` with
`trigger_mode: "on_create"` so the issue gets auto-triaged immediately.

The existing label-based trigger (`ta-needs-triage`) is preserved as a
separate `forward-labeled` job for manual re-triage. Both paths use OIDC
token exchange. The `ta-bot-triage` lock label prevents
double-processing when both triggers fire on the same issue.

**This PR should NOT be merged until June 1 rollout.**

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Triage forwarder on_create mode

  Scenario: new issue triggers auto-triage
    Given the triage forwarder workflow listens to issues opened events

    When a user creates a new issue
    Then the forwarder dispatches to triage-agent with trigger_mode on_create

  Scenario: label-based triage still works
    Given the triage forwarder workflow listens to issues labeled events

    When a user applies ta-needs-triage label to an issue
    Then the forwarder dispatches to triage-agent with trigger_mode label
```

## **Screenshots/Recordings**

N/A — workflow-only change, no UI impact.

### **Before**

### **After**

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

N/A — CI workflow change only.

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Every new issue will trigger an authenticated dispatch to
triage-agent, increasing automation surface and run volume; auth uses
the existing OIDC token-exchange pattern.
> 
> **Overview**
> Extends **triage-forwarder** so new issues can auto-dispatch to
`triage-agent` without waiting for the `ta-needs-triage` label.
> 
> The workflow now listens for **`issues` `opened`** in addition to
**`labeled`**, and splits the former single job into
**`forward-labeled`** (unchanged behavior: only when `ta-needs-triage`
is applied, payload `trigger_mode: "label"`) and **`forward-opened`**
(runs on `opened`, same OIDC → token exchange → repository dispatch
path, payload `trigger_mode: "on_create"`).
> 
> **Note:** PR description calls out coordinated rollout (not before
June 1) and downstream `ta-bot-triage` locking to avoid duplicate runs
when both paths could apply—those controls are not in this diff.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
270ed02. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…ed (#30783)

<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->

## **Description**

When `assetsUnifyState` is enabled, `useAddToken` only added tokens to
`TokensController`. However, `TransactionPayController` reads token
metadata from `AssetsController` (via `getStateForTransactionPay`) and
its retry mechanism (`subscribeAssetChanges`) only subscribes to
`AssetsController:stateChange`. This caused Predict deposit transactions
on Polygon to fail because the required pUSD token metadata was never
found.

The fix adds a call to `AssetsController.addCustomAsset()` alongside the
existing `TokensController.addToken()` when `assetsUnifyState` is
enabled. This ensures:
- Token metadata (decimals, symbol) is available in
`AssetsController.assetsInfo`
- `AssetsController:stateChange` fires, triggering the retry in
`TransactionPayController`
- `addCustomAsset` fetches balance and price data immediately

## **Changelog**

CHANGELOG entry: Fixed Predict deposit confirmation showing zero fiat
values when assetsUnifyState is enabled

## **Related issues**

Fixes: Predict deposit pUSD token not resolving in
TransactionPayController

## **Manual testing steps**

```gherkin
Feature: Predict deposit token resolution

  Scenario: user initiates a Predict deposit on Polygon
    Given the user has assetsUnifyState feature flag enabled
    And the user has not previously added pUSD to their token list

    When user initiates a Predict deposit transaction on Polygon
    Then the confirmation screen shows correct fiat values for the deposit amount
    And the pay-with token selector is functional
```

## **Screenshots/Recordings**

### **Before**

All fiat values show as $0.00 on the Predict deposit confirmation
screen. The `TransactionPayController` logs show "Missing token data"
for pUSD with `{decimals: true, symbol: true, fiatRates: true}`.

### **After**

Fiat values are correctly calculated. The token is added to both
`TokensController` and `AssetsController`, allowing
`TransactionPayController` to resolve the token metadata on retry.

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Scoped to confirmation token-add behind a feature flag; legacy
TokensController-only path unchanged when the flag is off.
> 
> **Overview**
> When **`assetsUnifyState`** is on, confirmation flows that call
**`useAddToken`** now register the token in **`AssetsController`** as
well as **`TokensController`**, using the selected EVM account id and a
CAIP asset id built from chain and address.
> 
> That mirrors what **`TransactionPayController`** expects (metadata
from **`AssetsController`** and retries on
**`AssetsController:stateChange`**), so pay/deposit confirmations can
show fiat amounts instead of zeros when the token was only in the legacy
token list.
> 
> Tests cover the flag off/on paths, **`addCustomAsset`** arguments, and
the existing “already added” skip behavior.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
43c460d. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->

## **Description**


- Fix security banner showing `[missing {{symbol}} value]` when token
symbol/name is unavailable (e.g. navigating from Trending to a token
without metadata)
- Fall back to `token.name` when `token.symbol` is empty, and use a
generic "This is a suspicious/malicious token" string when both are
missing
- Applied consistently across the inline banner, bottom sheet, and
sticky footer CTA warning flow


## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: Adds name fallback if symbol is undefined and shows new
string when both are undefined in security banners.

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-3301

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

<img width="381" height="747" alt="Screenshot 2026-05-29 at 17 48 12"
src="https://github.com/user-attachments/assets/0211dbde-24f0-4050-b0ac-60402d6dd659"
/>

<img width="385" height="775" alt="Screenshot 2026-05-29 at 17 48 21"
src="https://github.com/user-attachments/assets/359e1c72-abe7-4ce9-88ab-dedebcf6b851"
/>

## **Pre-merge author checklist**

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.



<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> UI copy and display-label fallbacks only; security interception
behavior is unchanged aside from clearer messaging when metadata is
incomplete.
> 
> **Overview**
> Fixes broken security trust copy when a token has no `symbol` (e.g.
from Trending): messages no longer show missing `{{symbol}}`
placeholders.
> 
> **Display label:** Token details flows now use `token.symbol ||
token.name` for inline banners, badge bottom sheets, and sticky-footer
buy/swap interception (`AssetOverviewContent`,
`TokenDetailsStickyFooter`).
> 
> **Copy fallbacks:** New `security_trust.*_no_symbol` strings in
`en.json`, plus `getResultTypeConfig` `getSheetDescription` branches for
empty/undefined symbols on Warning and Malicious. Inline
malicious/suspicious banners and the malicious sheet banner pick symbol
vs generic text the same way.
> 
> **Tests:** Coverage added for `getSheetDescription`, empty
`tokenSymbol` in `SecurityBadgeBottomSheet`, and name fallback in
`TokenDetailsStickyFooter`.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
f2cd0c0. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…uthorization list (#30297)

## **Description**

When building the EIP-7702 authorization list for a Pay delegation
transaction, the nonce was previously read from `NonceLock.nextNonce` —
the value computed by the nonce tracker, which accounts for
locally-pending transactions the Relay has no visibility into. This
could produce a nonce ahead of the true on-chain state, causing the
Relay to reject the authorization as invalid.

The fix reads `NonceLock.nonceDetails.params.nextNetworkNonce` instead —
the raw `eth_getTransactionCount` result that the nonce tracker already
fetches internally. This gives the committed on-chain nonce the Relay
needs to verify the authorization signature, without introducing a
separate provider call or adding a new Engine dependency.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Related to: #30798 

## **Manual testing steps**

```gherkin
Feature: EIP-7702 Pay delegation transaction

  Scenario: user submits a Pay transaction requiring EIP-7702 upgrade
    Given the account has not yet been delegated (not upgraded to EIP-7702)
    And the account has locally-pending transactions in the queue

    When user initiates a Pay transaction and confirms
    Then the authorization list is signed with the correct on-chain nonce
    And the transaction submits successfully via Relay
```

## **Screenshots/Recordings**

### **Before**

<!-- N/A — no UI change -->

### **After**

<!-- N/A — no UI change -->

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes nonce selection for EIP-7702 authorization signing in Pay
flows; wrong nonce would break Relay submission but scope is limited to
delegation authorization building.
> 
> **Overview**
> **EIP-7702 Pay delegation** now signs the authorization list with the
**committed on-chain nonce**
(`nonceLock.nonceDetails.params.nextNetworkNonce`) instead of the nonce
tracker’s **`nextNonce`**, which can include locally pending txs the
Relay cannot see.
> 
> Tests were updated to mock `networkClientId` on transaction meta and
to return the new nonce lock shape so
`KeyringController:signEip7702Authorization` still receives the expected
nonce.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
7d0387b. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->

## **Description**

Adds the "High price impact" warning surfaces to the QuickBuy bottom
sheet, matching what the Swaps design and Figma have. When a quote's
price impact meets or exceeds the error threshold, the rate tag in the
toolbar switches to a red "High price impact" pill (navigating to Quote
Details on tap), a new error-styled Price impact row appears in the
Quote Details screen, and tapping the Buy button intercepts to show a
"Very high price impact" confirmation view (reusing Bridge's
components).

<img height="790" alt="Simulator Screenshot - iPhone 17 Pro - 2026-05-29
at 11 19 21"
src="https://github.com/user-attachments/assets/1a144cc7-7198-411e-a21b-5b2183b9c64e"
/>
<img height="790" alt="Simulator Screenshot - iPhone 17 Pro - 2026-05-29
at 11 24 17"
src="https://github.com/user-attachments/assets/53cb8c78-1662-4821-a44c-6e665435faf7"
/>
<img height="790" alt="Simulator Screenshot - iPhone 17 Pro - 2026-05-29
at 11 38 20"
src="https://github.com/user-attachments/assets/b41270be-0d9c-458f-b2f4-8b7b0dd81a1d"
/>


## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes when users can submit trades on high price-impact quotes
(modal vs disabled button); incorrect routing could allow silent submits
or block valid trades.
> 
> **Overview**
> Quick Buy now surfaces **high price impact** the same way as Swaps:
inline warnings move off footer banners into a toolbar pill, quote
details, and an optional confirmation step before submit.
> 
> **Buy flow:** `QuickBuyContext` adds `handleBuy` so Buy no longer
calls `handleConfirm` directly. When `isPriceImpactError` and
`highPriceImpactModal` are on, Buy navigates to a new
`priceImpactConfirm` screen (Bridge `PriceImpactHeader` /
`PriceImpactFooter`); otherwise it confirms as before. If the modal
feature is off, high-impact quotes keep Buy disabled.
`useQuickBuyController` no longer blocks confirm on price impact
alone—that gate lives in context.
> 
> **UI:** `QuickBuyRateTag` can show a red “high price impact” pill;
quote details gain an error-styled price impact row when in error.
Footer `QuickBuyBanners` only show hardware/Solana; price-impact banners
are removed. Top Traders enables `highPriceImpactModal: true` in
`features.ts`.
> 
> Tests cover context routing, the confirm screen, and updated
banner/rate-tag behavior.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
5d87bb1. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…-681) (#30692)

## **Description**

Implements the **Add funds** portion of
[TMCU-681](https://consensyssoftware.atlassian.net/browse/TMCU-681):
when the user taps **Add funds** on the wallet home onboarding checklist
(fund step), the app opens the unified ramp buy flow with a preselected
asset when buyability data is available.

**Priority:** mainnet mUSD → mainnet native ETH (`eip155:1/slip44:60`).
If ramp token buyability is still loading, or neither asset is supported
for the user’s region, no `assetId` is passed (existing fallback: Token
Selection on V2 unified buy).

**Implementation:**
- `fundRampPriorityAssets.ts` — local CAIP-19 ids and minimal `TokenI`
stubs for buyability checks (no Earn / Deposit / Aggregator imports).
- `useWalletHomeOnboardingFundRampIntent` — resolves `{ rampIntent,
isLoading }` via `useTokensBuyability`.
- `useWalletHomeOnboardingChecklistFundPress` — passes resolved intent
to `goToBuy` after `RAMPS_BUTTON_CLICKED` analytics (TMCU-680 `location:
onboarding_checklist` unchanged).

## **Changelog**

CHANGELOG entry: Improved the wallet home onboarding **Add funds** step
to open the buy flow with mUSD or Ethereum preselected when those assets
are available for the user’s region.

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/TMCU-681

## **Manual testing steps**

```gherkin
Feature: Wallet home onboarding fund step ramp preselection

  Scenario: Add funds opens buy flow with mUSD when mainnet mUSD is buyable
    Given wallet home onboarding checklist is visible on the fund step
    And ramp token list includes supported mainnet mUSD for the user's region

    When user taps Add funds
    Then unified buy opens on Build Quote (V2) or equivalent buy flow with mUSD preselected

  Scenario: Add funds opens buy flow with ETH when mUSD is not buyable but ETH is
    Given wallet home onboarding checklist is visible on the fund step
    And mainnet mUSD is not buyable but native mainnet ETH is buyable

    When user taps Add funds
    Then buy flow opens with native Ethereum preselected

  Scenario: Add funds opens token selection when buyability is unresolved or neither asset is buyable
    Given wallet home onboarding checklist is visible on the fund step
    And ramp buyability is loading or neither mUSD nor ETH is buyable

    When user taps Add funds
    Then buy flow opens without a preselected asset (Token Selection on V2 unified buy)
```

## **Screenshots/Recordings**

### **Before**

Add funds opened the buy flow with no preselected token (Token Selection
on V2).

### **After**

Add funds opens Build Quote with mUSD or ETH when supported per
region/token list.



https://github.com/user-attachments/assets/e72e2d83-b65f-4a6f-b99a-9c2f4b167451



<!-- Add screenshots/recordings during manual QA if needed -->

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

[TMCU-681]:
https://consensyssoftware.atlassian.net/browse/TMCU-681?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Onboarding-only ramp navigation wiring with region buyability gating;
no auth, payments, or core wallet logic changes.
> 
> **Overview**
> Wallet home onboarding **Add funds** now opens the ramp buy flow with
a **preselected asset** when regional buyability allows it, instead of
always starting with no token chosen.
> 
> New logic defines a **mainnet mUSD → mainnet ETH** priority list
(CAIP-19 ids and minimal token stubs), resolves a `{ assetId }` **ramp
intent** via `useTokensBuyability`, and passes that intent into
`goToBuy` from the checklist fund press handler (analytics for
`onboarding_checklist` unchanged). While buyability is loading or
neither asset is supported, **`goToBuy` still runs with no intent** so
existing token-selection fallback behavior applies.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
bc080fe. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## Summary


<img width="914" height="743" alt="image"
src="https://github.com/user-attachments/assets/eaa554c6-4ad8-4411-be9c-dc49f3d6f6c1"
/>


- Changing the chain filter in the Quick Buy "Pay with" screen changed
the number of token rows, which re-measured the content-sized bottom
sheet and shifted the whole layout (poor UX).
- Introduces a single global height-locked container in `QuickBuyRoot`
that wraps all screens. Its height is measured once (on the first
layout) and locked, so navigating between screens (amount → pay with →
buy, etc.) and toggling chain filters no longer resizes the sheet.
- `QuickBuyPayWithScreen` now lets the token list and empty states fill
(`flex-1`) and scroll within the fixed height instead of dictating it.

## Changes

- `QuickBuyRoot.tsx`: add `lockedHeight` state + `handleContentLayout`
that captures the height once; wrap `renderActiveScreen(...)` in a
single `Box` container (`testID="quick-buy-content-container"`) with
`onLayout` and a fixed `height` once locked.
- `QuickBuyPayWithScreen.tsx`: token list `ScrollView` and both empty
states are `flex-1` (empty states centered) so they fill/scroll within
the locked height.
- Tests: `QuickBuyRoot` locks height on first layout and ignores later
differing heights; `QuickBuyPayWithScreen` asserts the list scroll view
fills available space.
- 
## **Changelog**

CHANGELOG entry: Locked Quick Buy bottom sheet height to prevent layout
shift

## Test plan

- [x] `yarn jest QuickBuyRoot.test.tsx QuickBuyPayWithScreen.test.tsx` —
18/18 passing
- [x] ESLint clean on changed files
- [ ] Manual: open Quick Buy → tap "Pay with" → toggle
All/Base/Solana/Linea and confirm the sheet height stays constant across
screens and filters

Made with [Cursor](https://cursor.com)



<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> UI-only layout and flex styling in the Social Leaderboard Quick Buy
flow; no auth, transactions, or data model changes.
> 
> **Overview**
> **Quick Buy** no longer resizes its bottom sheet when **Pay with**
content changes (chain filters, fewer token rows, or switching screens).
`QuickBuyRoot` wraps all routed screens in a container that records
height on the **first** `onLayout` and keeps that fixed height
afterward.
> 
> On **Pay with**, empty states and the token list use **`flex-1`** so
content scrolls inside the locked area instead of driving sheet size.
Tests cover first-layout lock, ignoring later layout events, and scroll
view flex growth.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
10319c5. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Xavier Brochard <xavier-brochard@users.noreply.github.com>
#29130)

…erformance testing

- WalletView page-object: update element locators for simplified
accessibility tree
- PerpsMarketDetailsView, PerpsMarketListView, PerpsOrderView: update
testIDs for new accessibility structure
- PredictDetailsPage, PredictMarketList: update locators after
Pressable→TouchableOpacity migration
- BrowserStackConfigBuilder: raise maxDepth to 70 (was 15) to expose
full homepage hierarchy
- Performance specs (login, onboarding, perps, predict): update
navigation and assertions
- PerformanceReporter/Tracker: reporting improvements and Sentry
publisher fixes
- aggregate-performance-reports.mjs, generate-slack-summary.sh: report
aggregation scripts

<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Changes are concentrated in E2E/CI and performance tooling; the only
app changes are non-security UI testability fixes (MaskedView pointer
events, token testIDs).
> 
> **Overview**
> This PR hardens **BrowserStack/Appium performance E2E** and aligns
measurements with a simpler accessibility tree: **iOS timers subtract
Appium round-trip overhead** via `TimerHelper` + `PlaywrightAssertions`
probes; **Android stays wall-clock**. CI adds
**`feature_flags_environment`** (client-config) separate from
**`build_variant`**, **`TEST_SRP_4`**, longer BS session/timeouts, and
**quality-gate failures fail retries** instead of marking runs flaky.
> 
> **Framework & infra:** Locators move to **testIDs / accessibility
IDs** (wallet, swaps, Perps, Predict, onboarding, MM Connect);
**interactive tap** polling on Android, `withSnapshotSettings`,
session-creation timing in reports, CI retries **2**. **Flows:**
optional interest questionnaire, GTM modals gated by **feature flags**
with UI fallback, richer Predict dismiss. **App:**
`pointerEvents="box-none"` on trade wallet `MaskedView` (iOS taps);
token rows get **`getAssetTestId`**.
> 
> **Specs:** Thresholds and assertions updated (e.g. asset view,
onboarding import, Perps uses **SRP_4** + tutorial helpers); several
**swap iOS** and **mm-connect** suites **skipped** (WAPI-1511).
**Risk:** mostly test/CI; small **production UI** touch on trade actions
and confirmation token list.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
66c814e. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…lows to use OIDC token exchange cp-7.80.0 (#30840)

<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->

## **Description**

This updates the `add-team-label` and `check-template-and-add-labels`
workflows to use OIDC token exchange.

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry:

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes how automation authenticates to GitHub (and planning);
misconfiguration could break PR/issue labeling until tokens and
permissions are correct.
> 
> **Overview**
> Two GitHub Actions workflows now obtain GitHub API tokens through
**OIDC token exchange** (`MetaMask/github-tools` `get-token@v1` and
`vars.TOKEN_EXCHANGE_URL`) instead of repository **secrets**
(`TEAM_LABEL_TOKEN`, `LABEL_TOKEN`).
> 
> **`add-team-label`** grants `id-token: write`, mints a read-only token
for `MetaMask/MetaMask-planning`, a separate token with `pull_requests:
write`, and passes both into `add-team-label@v1` as `planning-token` and
`team-label-token`.
> 
> **`check-template-and-add-labels`** adds `contents: read` and
`id-token: write`, fetches a scoped token (`issues: write`, `members:
read`, `pull_requests: write`), and wires `LABEL_TOKEN` to that output
for the existing script step.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
b51e09a. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
… and rename addTraitsToUser in ChoosePassword (#30500)

## **Description**

Part of the analytics cleanup workstream (#26686).

Migrates `AccountBackupStep1` from the deprecated `useMetrics` to
`useAnalytics` (renames the `isMetricsEnabled` local alias to
`isAnalyticsEnabled`). Renames `.addTraitsToUser()` → `.identify()` in
`ChoosePassword`. Updates both test files accordingly.

Files touched:
- `AccountBackupStep1/index.js` — migrate `useMetrics` → `useAnalytics`,
rename `isMetricsEnabled` → `isAnalyticsEnabled`
- `AccountBackupStep1/index.test.tsx` — replace
`jest.mock('../../hooks/useMetrics', ...)` factory with
`jest.mock('../../hooks/useAnalytics/useAnalytics')` +
`createMockUseAnalyticsHook`, rename `mockIsEnabled` →
`mockIsAnalyticsEnabled`
- `ChoosePassword/index.tsx` — rename `.addTraitsToUser` → `.identify`
- `ChoosePassword/index.test.tsx` — remove `addTraitsToUser` from mock
object, update assertions to `.identify`

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Closes: #30513
Refs: #26686

## **Manual testing steps**

N/A

## **Screenshots/Recordings**

### **Before**

N/A — no UI changes.

### **After**

N/A — no UI changes.

## **Pre-merge author checklist**

- [x] I've followed the [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md)
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md))

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, test
affected areas)
- [ ] I confirm that this PR addresses what is claimed in the PR title
- [ ] I confirm that I've manually reviewed the changes if not manually
tested

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Mechanical API renames on onboarding analytics opt-in and trait
identification; behavior should match prior useMetrics/addTraitsToUser
paths.
> 
> **Overview**
> Continues the analytics cleanup by swapping deprecated metrics APIs
for **`useAnalytics`** on onboarding backup and password flows.
> 
> **`AccountBackupStep1`** now uses `useAnalytics` instead of
`useMetrics`, with `isAnalyticsEnabled()` gating whether skip flows
dispatch straight to success or route through **`OptinMetrics`**. Tests
mock `useAnalytics` via `createMockUseAnalyticsHook` instead of the old
`useMetrics` factory.
> 
> **`ChoosePassword`** (OAuth post-wallet path) calls
**`metrics.identify()`** instead of **`addTraitsToUser()`** when sending
device and user-settings traits after analytics preference selection.
**`ChoosePassword`** tests drop `addTraitsToUser` from the mock and
assert **`identify`** instead.
> 
> No UI or navigation behavior changes beyond aligning with the unified
analytics hook naming.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
fd855af. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
…30856)

## **Description**

When a transaction type has fiat payments enabled via the
`confirmations_pay_fiat` remote feature flag, the app should
automatically select a fiat payment method (e.g. Apple Pay) if the user
has no usable crypto tokens. Previously, fiat auto-selection only
happened when explicitly requested via the `autoSelectFiatPayment`
navigation parameter (used only by the Money Account "Deposit funds"
flow).

This change makes fiat auto-selection work for **all** fiat-enabled
transaction types (e.g. Perps Deposit, Predict Deposit) when no usable
tokens are available, while preserving crypto as the preferred payment
method when tokens exist.

### Changes

1. **`useIsFiatPaymentAvailable` (new hook)** — Shared hook
encapsulating the fiat-availability check (`hasTransactionType` +
payment methods exist). Replaces duplicated inline logic across 3
consumers.

2. **`useAutomaticTransactionPayToken`** — Core fix: when `tokens.length
=== 0` (no usable non-disabled tokens), attempt fiat auto-selection
before giving up. The `autoSelectFiatPayment` explicit opt-in still
works as before.

3. **`useTransactionPayAvailableTokens`** — `hasTokens` now checks
`availableTokens.some(t => !t.disabled)` instead of
`availableTokens.length > 0`. Required tokens with zero balance were
counted as "available" despite being disabled (no gas), which prevented
the `BuySection` from rendering.

4. **`custom-amount-info.tsx`** — Renamed `hasTokens` →
`hasPaymentOption` to clarify the variable includes fiat availability.
Uses the new `useIsFiatPaymentAvailable` hook to prevent BuySection
flash when fiat will be auto-selected.

5. **`useFiatPaymentHighlightedActions`** — Replaced inline fiat-enabled
check with `useIsFiatPaymentAvailable`.

## **Changelog**

CHANGELOG entry: Fixed fiat payment method auto-selection for supported
transaction types when user has no crypto tokens

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/CONF-1435

## **Manual testing steps**

```gherkin
Feature: Fiat payment auto-selection

  Scenario: User with no usable tokens opens fiat-enabled deposit
    Given the user has no tokens with balance on the relevant chain
    And the transaction type (e.g. perpsDeposit) is in the fiat enabledTransactionTypes feature flag
    And at least one Ramps payment method is available

    When user opens the Add Funds screen for that transaction type
    Then a fiat payment method (e.g. Apple Pay) is automatically selected
    And the deposit keyboard is shown (not the Buy crypto button)

  Scenario: User with tokens opens fiat-enabled deposit
    Given the user has tokens with balance
    And the transaction type is in the fiat enabledTransactionTypes feature flag

    When user opens the Add Funds screen
    Then a crypto token is automatically selected (fiat is not forced)

  Scenario: User with no tokens opens non-fiat-enabled deposit
    Given the user has no usable tokens
    And the transaction type is NOT in the fiat enabledTransactionTypes feature flag

    When user opens the Add Funds screen
    Then the Buy crypto button is shown
```

## **Screenshots/Recordings**

### **Before**

### **After**

In the recordings `perpsDeposit` is fiat payment enabled,
`predictDeposit` is fiat payment disabled:



https://github.com/user-attachments/assets/ae22c510-0a21-4a30-be63-dbe25b387249



https://github.com/user-attachments/assets/1b7749c2-5858-4768-bfa8-333868286f66



## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches default payment selection and deposit UI for multiple
transaction types; behavior depends on remote fiat flags and Ramps
payment methods, with test coverage but real-device flows should be
spot-checked.
> 
> **Overview**
> Fiat-enabled deposit flows now **auto-select a Ramps payment method**
when the user has no usable crypto tokens, not only when
`autoSelectFiatPayment` is passed from Money Account deposit.
> 
> A new **`useIsFiatPaymentAvailable`** hook centralizes “transaction
type allowed by fiat flags + at least one payment method.”
**`useAutomaticTransactionPayToken`** runs fiat auto-selection when
`autoSelectFiatPayment` is set **or** the filtered usable token list is
empty, and stops falling back to a required target token when fiat is
unavailable. **`useTransactionPayAvailableTokens`** treats `hasTokens`
as “any non-disabled token” so disabled required tokens no longer block
fiat/Buy UI. **`custom-amount-info`** uses **`hasPaymentOption`**
(crypto or fiat) for keyboard, Pay With, and Buy section so fiat-enabled
screens avoid a Buy flash before auto-selection.
> 
> Tests cover the new hook, disabled-token `hasTokens` behavior, and
updated auto-select expectations.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
8b19714. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…d-labels` (#30875)

<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->

## **Description**

`token-exchange-service` is having a permission issue, so to unblock CI
while waiting for that to be resolved I've added a temporary fallback to
the Patroll token.

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry:

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Labeling automation may run with a long-lived PAT instead of a
short-lived exchanged token, which affects credential handling and
should be reverted once token exchange is fixed.
> 
> **Overview**
> Unblocks the **Check template and add labels** workflow when
`token-exchange-service` cannot mint a token.
> 
> The **Get access token** step now uses `continue-on-error: true` so a
failed MetaMask `get-token` action does not fail the job. `LABEL_TOKEN`
for the labeling script is set to the exchanged token when present,
otherwise **`secrets.LABEL_TOKEN`** (Patroll PAT) as a temporary
fallback.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
19668bf. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

- Updates to supported price-api chains
- Improvement for `MulticallClient` in assets-controller

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: null

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-3304

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

- [X] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [X] I've completed the PR template to the best of my ability
- [X] I've included tests if applicable
- [X] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [X] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> <sup>[Cursor Bugbot](https://cursor.com/bugbot) is generating a
summary for commit 318be02. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…nd history tabs (#30718)

## **Description**

Adds the new full-page Predict Positions destination for PRED-900. The
screen is gated behind `predictPortfolio.enabled`, uses Positions
terminology for the route/title/tabs, and is powered by the shared
Predict portfolio model.

This PR includes:

- New `Routes.PREDICT.POSITIONS` route and typed
`PredictPositionsParams`.
- New `PredictPositionsView` with fixed Predict header, `Positions`
title, `Active positions` and `History` tabs.
- New `PredictPositionsViewHeader` for available balance, optional
Unrealized P&L, and Claim CTA.
- Shared `PredictPositionsEmpty` with Browse markets CTA.
- `PredictPositionsList` for active/open positions only.
- `PredictPositionsHistoryList` wrapper around `PredictTransactionsView`
for v1 history rendering.
- `PredictTransactionsView` support for custom empty state and spacing
overrides.
- Unit and component-view coverage for route gating, tabs, empty states,
claim CTA, history wrapper, and screen presets.
- Removal of the temporary Positions button from the Predict feed.

## **Changelog**

CHANGELOG entry: Added a new Positions screen for Predict users to view
active positions and history

## **Related issues**

Fixes:
[PRED-900](https://consensyssoftware.atlassian.net/browse/PRED-900)

## **Manual testing steps**

```gherkin
Feature: Predict Positions screen

  Scenario: user views active positions
    Given the predictPortfolio feature flag is enabled
    And the user has Predict available balance and open positions
    When user navigates to the Predict Positions route
    Then the Positions title is shown
    And the available balance is shown
    And Unrealized P&L is shown only when the display threshold is met
    And only open positions are listed under Active positions

  Scenario: user views claimable winnings
    Given the user has claimable Predict winnings
    When user opens the Predict Positions route
    Then the Claim CTA is shown in the summary header

  Scenario: user views history
    Given the user is on the Predict Positions route
    When user taps History
    Then Predict transaction history is shown

  Scenario: user sees empty state
    Given the user has no active positions or history
    When user opens Active positions or History
    Then the shared empty state is shown
    When user taps Browse markets
    Then user returns to the Predict market list without creating duplicate nested feeds

  Scenario: route is feature-flag disabled
    Given the predictPortfolio feature flag is disabled
    When user attempts to navigate to the Predict Positions route
    Then user is returned to the Predict market list
```

## **Screenshots/Recordings**

### **Before**

N/A - new screen route.

### **After**


https://github.com/user-attachments/assets/d628042f-265d-471e-a4b5-1a8e9bfe058d



## **Testing**

- `yarn jest
app/components/UI/Predict/views/PredictPositionsView/PredictPositionsView.test.tsx
app/components/UI/Predict/routes/index.test.tsx
app/components/UI/Predict/components/PredictPositionsEmpty/PredictPositionsEmpty.test.tsx
app/components/UI/Predict/components/PredictPositionsList/PredictPositionsList.test.tsx
app/components/UI/Predict/components/PredictPositionsHistoryList/PredictPositionsHistoryList.test.tsx
app/components/UI/Predict/views/PredictTransactionsView/PredictTransactionsView.test.tsx
app/components/UI/Predict/views/PredictFeed/PredictFeed.test.tsx`
- `yarn jest -c jest.config.view.js
app/components/UI/Predict/views/PredictPositionsView/PredictPositionsView.view.test.tsx
--runInBand --silent --coverage=false`
- `yarn eslint app/components/UI/Predict/Predict.testIds.ts
app/components/UI/Predict/components/PredictActivity/PredictActivity.tsx
app/components/UI/Predict/components/PredictPositionsEmpty/PredictPositionsEmpty.test.tsx
app/components/UI/Predict/components/PredictPositionsEmpty/PredictPositionsEmpty.tsx
app/components/UI/Predict/components/PredictPositionsEmpty/index.ts
app/components/UI/Predict/components/PredictPositionsHistoryList/PredictPositionsHistoryList.test.tsx
app/components/UI/Predict/components/PredictPositionsHistoryList/PredictPositionsHistoryList.tsx
app/components/UI/Predict/components/PredictPositionsHistoryList/index.ts
app/components/UI/Predict/components/PredictPositionsList/PredictPositionsList.test.tsx
app/components/UI/Predict/components/PredictPositionsList/PredictPositionsList.tsx
app/components/UI/Predict/components/PredictPositionsList/index.ts
app/components/UI/Predict/components/PredictPositionsViewHeader/PredictPositionsViewHeader.test.tsx
app/components/UI/Predict/components/PredictPositionsViewHeader/PredictPositionsViewHeader.tsx
app/components/UI/Predict/components/PredictPositionsViewHeader/index.ts
app/components/UI/Predict/routes/index.test.tsx
app/components/UI/Predict/routes/index.tsx
app/components/UI/Predict/types/navigation.ts
app/components/UI/Predict/views/PredictFeed/PredictFeed.test.tsx
app/components/UI/Predict/views/PredictFeed/PredictFeed.tsx
app/components/UI/Predict/views/PredictPositionsView/PredictPositionsView.test.tsx
app/components/UI/Predict/views/PredictPositionsView/PredictPositionsView.tsx
app/components/UI/Predict/views/PredictPositionsView/PredictPositionsView.view.test.tsx
app/components/UI/Predict/views/PredictPositionsView/index.tsx
app/components/UI/Predict/views/PredictTransactionsView/PredictTransactionsView.test.tsx
app/components/UI/Predict/views/PredictTransactionsView/PredictTransactionsView.tsx
app/constants/navigation/Routes.ts tests/component-view/mocks.ts
tests/component-view/renderers/predictPositions.tsx`

ESLint completed with 0 errors and existing warnings for deprecated
`HeaderSearch`, deprecated `TabEmptyState`, and `no-void` in
`PredictTransactionsView`.

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
- [ ] I've tested with a power user scenario
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.


[PRED-900]:
https://consensyssoftware.atlassian.net/browse/PRED-900?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches portfolio display, claim flow (action guard), and navigation
gating; large UI surface but behind a feature flag with extensive tests.
> 
> **Overview**
> Adds a **feature-flagged** full-page Predict **Positions** destination
(`Routes.PREDICT.POSITIONS`) behind `predictPortfolio.enabled`, with a
route wrapper that redirects to the market list when the flag is off.
> 
> **`PredictPositionsView`** composes a summary header (available
balance, optional unrealized P&L, guarded **Claim** CTA), **Active
positions** / **History** tabs (optional `initialTab` route param), and
tab panels that stay mounted but hidden for accessibility. New pieces
include **`PredictPositionsList`** (open positions only, skeletons,
privacy mode, market-details navigation),
**`PredictPositionsHistoryList`** (reuses **`PredictTransactionsView`**
with shared empty state and padding overrides), and
**`PredictPositionsEmpty`** (Browse markets via `popToTop` or navigate
to market list).
> 
> **`usePredictPortfolio`** exposes **`isOpenPositionsLoading`**
separately from claimable-position loading so the UI can show P&L
skeletons vs empty states correctly. **`PredictTransactionsView`** /
**`PredictActivity`** accept custom empty states and layout overrides.
i18n, test IDs, navigation types, component-view mocks/renderers, and
broad unit/view tests cover the new flow.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
e8b3b8f. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## Summary

- Add an opt-in `beforeRemove` cleanup path to
`useClearConfirmationOnBackSwipe`.
- Enable that cleanup for the Predict claim confirmation screen.
- Guard against duplicate rejection when both gesture and route removal
events fire.

## Root cause

The Predict claim confirmation could be dismissed through route removal
without the existing `gestureEnd` cleanup firing. That left the
transaction approval unresolved and
`PredictController.pendingClaims[address]` stuck, so returning to the
Predict UI showed the “Claim already in progress” toast.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes confirmation reject/navigation timing and Predict
pending-claim state; behavior is covered by new tests but affects
transaction approval dismissal paths.
> 
> **Overview**
> Fixes Predict claim confirmations leaving **`pendingClaims`** set when
the screen is dismissed via route removal (not only swipe
**`gestureEnd`**), which blocked later claims with “already in
progress.”
> 
> Adds **`PredictController.clearPendingClaim()`** and wires the claim
confirmation UI to call it through an expanded
**`useClearConfirmationOnBackSwipe`**: optional **`beforeRemove`** /
gesture-aware rejection, **`onBeforeReject`** cleanup, single-reject
deduping, and optional **`skipNavigation`** on reject.
**`isConfirmationSubmitting`** in confirmation context is set while the
claim CTA runs so back/gesture dismissal does not reject or clear state
mid-submit.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
4df7bbc. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->

## **Description**

Add gainers and losers section in Explore/Now

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: add gainers and losers section in Explore/Now

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-3298

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> UI and navigation param changes in Explore/Perps with no auth,
payments, or data-persistence logic beyond existing sort preferences.
> 
> **Overview**
> **Explore → Now** adds **Gainers / Losers** pills on **Perps movers**,
filters markets by sign of 24h price change, and sorts gainers
descending / losers ascending via new
`filterAndSortByPriceChangeDirection` in `usePerpsFeed`.
> 
> **View all** now opens the perps market list with matching sort:
`navigateToPerpsMarketList` takes an options object (`sortDirection`,
optional `source`) and passes `defaultSortDirection` through navigation
into `usePerpsMarketListView`, so list ordering aligns with the selected
pill (not only saved user prefs). Copy added for the new pill labels in
`en.json`.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
61a03c3. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->

## **Description**

Add world cup predictions in explore (FF gated)

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: add world cup predictions in explore (FF gated)


## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-3203 &
https://consensyssoftware.atlassian.net/browse/ASSETS-3204

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**


https://github.com/user-attachments/assets/68bb1434-b489-46d0-af3a-aa82b6ea3c48


<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> UI and navigation changes behind existing Predict/World Cup flags; no
auth or payment logic touched.
> 
> **Overview**
> Explore **Now** and **Sports** can show a **World Cup predictions**
carousel when the World Cup screen feature flag is on, instead of the
usual category feeds. A new `useWorldCupPredictionsFeed` loads World Cup
markets and disables the standard `usePredictionsFeed` while active so
only one preview fetches at a time.
> 
> **View all** routes to the dedicated Predict World Cup screen
(`navigateToExploreWorldCupPredictions`) with explore entry point and
the **All** tab; otherwise behavior is unchanged. List navigation now
always passes an explicit `tab` (including `trending`). Copy adds
`predict.world_cup.predictions_title`. Tests cover navigation and both
tab variants.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
2026668. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@pull pull Bot locked and limited conversation to collaborators Jun 1, 2026
@pull pull Bot added the ⤵️ pull label Jun 1, 2026
@pull pull Bot merged commit 02c85c2 into Reality2byte:main Jun 1, 2026
5 of 16 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.